---
title: Life of a value
sidebar_position: 2
description: An explanation of when and how Mojo creates values.
---

The life of a value in Mojo begins when a variable is initialized and continues
up until the value is last used, at which point Mojo destroys it. This page
describes how every value in Mojo is created, copied, and moved. (The next
page describes [how values are
destroyed](/mojo/manual/lifecycle/death).)

All data types in Mojo—including basic types in the standard library such as
[`Bool`](/mojo/stdlib/builtin/bool/Bool), [`Int`](/mojo/stdlib/builtin/int/Int),
and [`String`](/mojo/stdlib/collections/string/string/String)—are defined as
[structs](/mojo/manual/structs). This means the creation and destruction of any
piece of data follows the same lifecycle rules, and you can define your own data
types that work exactly the same way.

Mojo structs don't get any default lifecycle methods, such as a
constructor, copy constructor, or move constructor. That means you can define
a struct without a constructor, but then you can't instantiate it, and it
would be useful only as a sort of namespace for static methods. For example:

```mojo
struct NoInstances:
    var state: Int

    @staticmethod
    fn print_hello():
        print("Hello world!")
```

Without a constructor, this cannot be instantiated, so it has no lifecycle. The
`state` field is also useless because it cannot be initialized (Mojo structs do
not support default field values—you must initialize them in a constructor).

So the only thing you can do is call the static method:

```mojo
NoInstances.print_hello()
```

```output
Hello world!
```

## Constructor

To create an instance of a Mojo type, it needs the `__init__()` constructor
method. The main responsibility of the constructor is to initialize all fields.
For example:

```mojo
struct MyPet:
    var name: String
    var age: Int

    fn __init__(out self, name: String, age: Int):
        self.name = name
        self.age = age
```

Now we can create an instance:

```mojo
var mine = MyPet("Loki", 4)
```

An instance of `MyPet` can also be read
and destroyed, but it currently can't be copied or moved.

We believe this is a good default starting point, because there are no built-in
lifecycle events and no surprise behaviors. You—the type author—must
explicitly decide whether and how the type can be copied or moved, by
implementing the copy and move constructors.

The pattern shown above—a constructor that takes an argument for each of the
struct's fields and initializes the fields directly from the arguments—is called
a *field-wise constructor*. It's a common enough pattern that Mojo includes a
[`@fieldwise_init`](/mojo/manual/decorators/fieldwise-init) decorator to
synthesize the field-wise constructor. So you can rewrite the previous example
like this:

```mojo
@fieldwise_init
struct MyPet:
    var name: String
    var age: Int
```

:::note

Mojo does not require a destructor to destroy an instance. But in some cases you
may need to define a custom destructor to release resources (for example, if a
struct dynamically allocates memory using
[`UnsafePointer`](/mojo/stdlib/memory/unsafe_pointer/UnsafePointer)). We'll
discuss that more in [Death of a value](/mojo/manual/lifecycle/death).

:::

:::note The "constructor" name

In a Python class, object construction happens across both the `__new__()` and
`__init__()` methods, so the `__init__()` method is technically just the
initializer for attributes (but it's often still called the constructor).
However, in a Mojo struct, there is no `__new__()` method, so we prefer to
always call `__init__()` the constructor.

:::

### Overloading the constructor

Like any other function/method, you can
[overload](/mojo/manual/functions#overloaded-functions) the
`__init__()` constructor to initialize the object with different arguments. For
example, you might want a default constructor that sets some default values and
takes no arguments, and then additional constructors that accept more arguments.

Just be aware that, in order to modify any fields, each constructor must
declare the `self` argument with the [`out`
convention](/mojo/manual/values/ownership#argument-conventions). If you
want to call one constructor from another, you simply call upon that
constructor as you would externally (you don't need to pass `self`).

For example, here's how you can delegate work from an overloaded constructor:

```mojo
struct MyPet:
    var name: String
    var age: Int

    fn __init__(out self):
        self.name = ""
        self.age = 0

    fn __init__(out self, name: String):
        self = MyPet()
        self.name = name
```

### Field initialization

Notice in the previous example that, by the end of each constructor, all fields
must be initialized. That's the only requirement in the constructor.

In fact, the `__init__()` constructor is smart enough to treat the `self`
object as fully initialized even before the constructor is finished, as long
as all fields are initialized. For example, this constructor can pass around
`self` as soon as all fields are initialized:

```mojo
fn use(arg: MyPet):
    pass

struct MyPet:
    var name: String
    var age: Int

    fn __init__(out self, name: String, age: Int, cond: Bool):
        self.name = name
        if cond:
            self.age = age
            use(self)  # Safe to use immediately!

        self.age = age
        use(self)  # Safe to use immediately!
```

### Constructors and implicit conversion

Mojo supports implicit conversion from one type to another. Implicit conversion
can happen when one of the following occurs:

- You assign a value of one type to a variable with a different type.
- You pass a value of one type to a function that requires a different type.
- You return a value of one type from a function that specifies a different
  return type.

In all cases, implicit conversion is supported when the target type
defines a constructor that meets the following criteria:

- Is declared with the `@implicit` decorator.
- Has a single required, non-keyword argument of the source type.

For example:

```mojo
var a = Source()
var b: Target = a
```

Mojo implicitly converts the `Source` value in `a` to a `Target` value if
`Target` defines a matching constructor like this:

```mojo
struct Target:

    @implicit
    fn __init__(out self, s: Source): ...
```

With implicit conversion, the assignment above is essentially identical to:

```mojo
var b = Target(a)
```

In general, types should only support implicit conversions when the conversion
is lossless, and ideally inexpensive. For example, converting an integer to a
floating-point number is usually lossless (except for very large positive and
negative integers, where the conversion may be approximate), but converting a
floating-point number to an integer is very likely to lose information. So
Mojo supports implicit conversion from `Int` to `Float64`, but not the reverse.

The constructor used for implicit conversion can take optional arguments, so
the following constructor would also support implicit conversion from `Source`
to `Target`:

```mojo
struct Target:

    @implicit
    fn __init__(out self, s: Source, reverse: Bool = False): ...
```

Implicit conversion can fail if Mojo can't unambiguously match the conversion to
a constructor. For example, if the target type has two overloaded constructors
that take different types, and each of those types supports an implicit
conversion from the source type, the compiler has two equally-valid paths to
convert the values:

```mojo
struct A:
    @implicit
    fn __init__(out self, s: Source): ...

struct B:
    @implicit
    fn __init__(out self, s: Source): ...

struct OverloadedTarget:
    @implicit
    fn __init__(out self, a: A): ...
    @implicit
    fn __init__(out self, b: B): ...

var t = OverloadedTarget(Source()) # Error: ambiguous call to '__init__': each
                                   # candidate requires 1 implicit conversion
```

In this case, you can fix the issue by explicitly casting to one of the
intermediate types. For example:

```mojo
var t = OverloadedTarget(A(Source())) # OK
```

Mojo applies at most one implicit conversion to a variable. For example:

```mojo
var t: OverloadedTarget = Source() # Error: can't implicitly convert Source
                                   # to Target
```

Would fail because there's no direct conversion from `Source` to
`OverloadedTarget`.

For structs with a single field, you can generate an implicit constructor with
the `@fieldwise_init("implicit")` decorator.

```mojo
@fieldwise_init("implicit")
struct Counter:
    var count: Int

def main():
    var c: Counter = 5  # implicitly converts from Int
```


## Copy constructor

In Mojo, a value can be copied either *explicitly* or  *implicitly*:

```mojo
# Explicit copy
var s = "Test string"
var s2 = s.copy()

# Implicit copy
var i = 15
var i2 = i
```

To make a struct explicitly copyable, you need to:

- Add the `Copyable` trait.
- (Optionally) define a custom `__copyinit__()` method if needed.

If you simply add the `Copyable` trait, Mojo will generate a default
`__copyinit__()` method for you, which copies each field of the existing value
into the new value. The `Copyable` trait also defines a default `copy()` method, which
provides a more user-friendly way to copy a value than invoking the
copy constructor directly.

```mojo
@fieldwise_init
struct MyPet(Copyable):
    var name: String
    var age: Int
```

Now this code works to make a copy:

```mojo
var mine = MyPet("Loki", 4)
var yours = mine.copy()
```

:::note

Technically, you *could* make a struct with a copy constructor and *not* add the
`Copyable` trait, but this is not recommended. Mojo would be able to copy the
value, but you couldn't use the struct with any generic containers or functions
that require the `Copyable` trait.

:::

The generated copy constructor simply copies each field from the existing value
into the new value. For example, if you wrote the `__copyinit__()` method for
`MyPet`, it would look like this:

```mojo
fn __copyinit__(out self, existing: Self):
    self.name = existing.name
    self.age = existing.age
```

This default copy constructor works in most cases, but there are a few cases
where you need to define a custom copy constructor:

- One or more of the struct's fields is not `Copyable`.
- The struct includes a non-owning type (like
  [`UnsafePointer`](/mojo/stdlib/memory/unsafe_pointer/UnsafePointer)), and you
  want to make a deep copy of the data.
- The struct holds other resources (like file descriptors or network sockets)
  that need to be managed.

### Custom copy constructor

What makes Mojo's copy behavior different, compared to other languages, is that
`__copyinit__()` is designed to perform a deep copy of all fields in the type
(as per [value semantics](/mojo/manual/values/value-semantics)). That is,
it copies heap-allocated values, rather than just copying the pointer.

However, the Mojo compiler doesn't enforce this, so it's the type author's
responsibility to implement `__copyinit__()` with value semantics.

For example, here's a new `HeapArray` type with a custom copy constructor that
performs a deep copy:

```mojo
struct HeapArray(Copyable):
    var data: UnsafePointer[Int, MutOrigin.external]
    var size: Int
    var cap: Int

    fn __init__(out self, size: Int, val: Int):
        self.size = size
        self.cap = size * 2
        self.data = alloc[Int](self.cap)
        for i in range(self.size):
            (self.data + i).init_pointee_copy(val)

    fn __copyinit__(out self, existing: Self):
        # Deep-copy the existing value
        self.size = existing.size
        self.cap = existing.cap
        self.data = alloc[Int](self.cap)
        for i in range(self.size):
            (self.data + i).init_pointee_copy(existing.data[i])
        # The lifetime of `existing` continues unchanged

    fn __del__(deinit self):
        # We must free the heap-allocated data, but
        # Mojo knows how to destroy the other fields
        for i in range(self.size):
            (self.data + i).destroy_pointee()
        self.data.free()

    fn append(mut self, val: Int):
        # Update the array for demo purposes
        if self.size < self.cap:
            (self.data + self.size).init_pointee_copy(val)
            self.size += 1
        else:
            print("Out of bounds")

    fn dump(self):
        # Print the array contents for demo purposes
        print("[", end="")
        for i in range(self.size):
            if i > 0:
                print(", ", end="")
            print(self.data[i], end="")
        print("]")
```

Notice that `__copyinit__()` does not copy the `UnsafePointer` value (doing so
would make the copied value refer to the same `data` memory address as the
original value, which is a shallow copy). Instead, we initialize a new
`UnsafePointer` to allocate a new block of memory, and then copy over all the
heap-allocated values (this is a deep copy).

Thus, when we copy an instance of `HeapArray`, each copy has its own set of
values on the heap, so changes to one array do not affect the other, as shown
here:

```mojo
fn copies():
    var a = HeapArray(2, 1)
    var b = a.copy()  # Calls the copy constructor
    a.dump()  # Prints [1, 1]
    b.dump()  # Prints [1, 1]

    b.append(2)  # Changes the copied data
    b.dump()  # Prints [1, 1, 2]
    a.dump()  # Prints [1, 1] (the original did not change)
```

Two other things to note from the `__copyinit__()` method:


- The `existing` argument is type `Self` (capital "S"). `Self` is an alias for
  the current type name (`HeapArray`, in this example). Using this alias is a
  best practice to avoid any mistakes when referring to the current struct name.

- The `existing` argument is immutable because the default [argument
   convention](/mojo/manual/values/ownership#argument-conventions) is
   `read`—this is a good thing because this function should not modify the
   contents of the value being copied.

:::note

In `HeapArray`, we must use the `__del__()` destructor to free the
heap-allocated data when the `HeapArray` lifetime ends, but Mojo automatically
destroys all other fields when their respective lifetimes end. We'll discuss
this destructor more in [Death of a value](/mojo/manual/lifecycle/death).

:::

If your type doesn't use any pointers for heap-allocated data, then writing the
constructor and copy constructor is all boilerplate code that you shouldn't have
to write. For most structs that don't manage memory explicitly, you can just add
the `Copyable` trait to your struct definition and Mojo will synthesize the
`__copyinit__()` method.

:::note

Mojo also calls upon the copy constructor when a value is passed to a
function that takes the argument as
[`var`](/mojo/manual/values/ownership#transfer-arguments-var-and-)
*and* when the lifetime of the given value does *not* end at that point. If the
lifetime of the value does end there (usually indicated with the transfer
sigil `^`), then Mojo instead invokes the move constructor.

:::

### Implicitly-copyable types

To make a type *implicitly copyable*, add the `ImplicitlyCopyable` trait:

```mojo
@fieldwise_init
struct MyPair(ImplicitlyCopyable, Movable):
    var first: Int
    var second: Int

def main():
    pair = MyPair(3, 4)
    copy = pair
    print(pair.first, copy.second)
```

The `ImplicitlyCopyable` trait inherits from `Copyable`, so adding
`ImplicitlyCopyable` to your type gives you a copy constructor and a default `copy()`
method. The trait doesn't define any methods of its own: it serves as a signal
to the compiler that it can insert calls to `__copyinit__()` as needed. For
example, in the previous example, the compiler might generate code equivalent
to:

```mojo
pair = MyPair(3, 4)
copy = MyPair.__copyinit__(pair)
```

A type should be implicitly copyable only if copying the type is inexpensive and
has no side effects. Unnecessary copies can be a big drain on memory and
performance, so use this trait with caution.

In particular, any type that dynamically allocates memory or manages other
resources probably shouldn't be implicitly copyable.

## Move constructor

Although copying values provides predictable behavior that matches Mojo's
[value semantics](/mojo/manual/values/value-semantics), copying some data
types can be a significant hit on performance.

Mojo uses the move constructor to transfer ownership of a value from one
variable to another, **without** copying its fields. A value that's copyable
but doesn't have a move constructor can still be transferred by making a copy
and then discarding the original. So in this case, the move constructor serves
as an optimization.

To make a type *movable*:

- Add the `Movable` trait.
- (Optionally) implement a custom `__moveinit__()` method.

Note that [register-passable values](/mojo/manual/decorators/register-passable)
types are automatically movable, and **cannot** define a custom `__moveinit__()`
method.

Here's a movable version of the `MyPet` struct:

```mojo
@fieldwise_init
struct MyPet(Copyable, Movable):
    var name: String
    var age: Int
```

Here's an example showing how to invoke the move constructor for `MyPet`:

```mojo
fn moves():
    var a = MyPet("Bobo", 2)

    print(a.name) # Prints "bobo"

    var b = a^ # the lifetime of `a` ends here

    print(b.name) # prints "bobo"
    # print(a.name)  # ERROR: use of uninitialized value 'a'
```

If you include the `Movable` trait and don't define a move constructor, Mojo
generates a default move constructor for you. This move constructor simply moves
each of the fields to the new instance.

The generated move constructor for `MyPet` would look like this if you wrote
it yourself:

```mojo
fn __moveinit__(out self, deinit existing: Self):
    self.name = existing.name^
    self.age = existing.age
```

The move constructor takes its `existing` argument using the `deinit`
[argument convention](/mojo/manual/values/ownership#argument-conventions), which
grants exclusive ownership of the value and marks it as destroyed at the end of
the function. (For more information on the `deinit` convention, see
[Field lifetimes during destruct and move](/mojo/manual/lifecycle/death#field-lifetimes-during-destruct-and-move)).

The move constructor uses the transfer sigil (`^`) to indicate that ownership of
the `name` value is being transferred from `existing` to `self`. For
register-passable types like `Int`, the transfer sigil is omitted:
register-passable types are always treated as movable, but they can't define
custom move constructors or destructors, so there's no special logic to run for
a move.

At the end of the `__moveinit__()` method, Mojo immediately invalidates the
original variable, preventing any access to it. It does **not** call the
destructor, since that would destroy resources that have been transferred to the
new instance. Invalidating the original variable is important to avoid memory
errors on heap-allocated data, such as use-after-free and double-free errors.

:::note

A move constructor is **not required** to transfer ownership of a
value. If a value is copyable but not movable, Mojo can copy the value and
invalidate the original instance. You can learn more in the section about
[ownership
transfer](/mojo/manual/values/ownership#transfer-arguments-var-and-).

If copying a type is expensive, moving it with `__moveinit__()` is much
more efficient. For example, if a type has heap-allocated data, `__copyinit__()`
typically needs to allocate new storage to make a deep copy of the data.

For types without heap-allocated fields, you get no real benefit from the move
constructor. Making copies of simple data types on the stack, like integers,
floats, and booleans, is very cheap. Yet, if you allow your type to be copied,
then there's generally no reason to disallow moves.

:::


### Custom move constructor

In practice, structs very rarely require a custom `__moveinit__()`. A type might
require a custom `__moveinit__()` if it has a pointer to itself or one of its
fields, for example, since the struct's location in memory changes when it's
moved.

The `__moveinit__()` method performs a consuming move: it [transfers
ownership](/mojo/manual/values/ownership#transfer-arguments-var-and-) of a
value from one variable to another when the original variable's lifetime ends
(also called a "destructive move").

A critical feature of `__moveinit__()` is that it takes the incoming value as
a `deinit` argument, meaning this method gets unique ownership of the value. Moreover,
because this is a dunder method that Mojo calls only when performing a move
(during ownership transfer), the `existing` argument is guaranteed to be a
mutable reference to the original value, *not a copy* (unlike other methods that
may declare an argument as `var`, but might receive the value as a copy if the
method is called without the [`^` transfer
sigil](/mojo/manual/values/ownership#transfer-arguments-var-and-)).
That is, Mojo calls this move constructor *only* when the original variable's
lifetime actually ends at the point of transfer.


## Move-only and immovable types

To ensure your type can't be implicitly copied, you can make it "move-only" by
making it `Movable` but not `Copyable`. A move-only type can be
passed to other variables and passed into functions with any argument convention
(`read`, `mut`, and `var`)—the only catch is that you must use the `^`
transfer sigil to end the lifetime of a move-only type when assigning it to a
new variable or when passing it as a `var` argument. The
[`OwnedPointer`](/mojo/stdlib/memory/owned_pointer/OwnedPointer/) is an
example of a move-only type: because it is designed to provide clear single
ownership of a stored value, the `OwnedPointer` can be moved, but not copied.

In some (rare) cases, you may not want a type to be copyable *or* movable. The
[`Atomic`](/mojo/stdlib/os/atomic/Atomic/) type is an example of a type that's
neither copyable or movable.

## Trivial types

So far, we've talked about values that live in memory, which means they have an
identity (an address) that can be passed around among functions (passed "by
reference"). This is great for most types, and it's a safe default for large
objects with expensive copy operations. However, it's inefficient for tiny
things like a single integer or floating point number. We call these types
"trivial" because they are just "bags of bits" that should be copied, moved,
and destroyed without invoking any custom lifecycle methods.

Trivial types are the most common types that surround us, and from a language
perspective, Mojo doesn't need special support for these written in a struct.
Usually, these values are so tiny that they should be passed around in CPU
registers, not indirectly through memory.

As such, Mojo provides a struct decorator to declare these types of values:
`@register_passable("trivial")`. This decorator tells Mojo that the type should
be copyable and movable but that it has no user-defined logic for this (no
custom copy constructor or move constructor). It also tells Mojo to pass the
value in CPU registers whenever possible, which has clear performance benefits.

You'll see this decorator on types like `Int` in the standard library:

```mojo
@register_passable("trivial")
struct Int:
    ...
```

We expect to use this decorator pervasively on Mojo standard library types, but
it is safe to ignore for general application-level code.

For more information, see the [`@register_passable`
documentation](/mojo/manual/decorators/register-passable).

### Trivial lifecycle methods

The use of a decorator to identify trivial types will be phased out in favor
of a more granular set of aliases, which are boolean flags set by the compiler:

- The `Copyable` trait defines the alias `__copyinit__is_trivial`, which is an
  optimization hint that guarantees that the value can be copied by its bits
  from one location to another without causing any side effects.

- The `Movable` trait defines the alias `__moveinit__is_trivial`, which is an
  optimization hint that guarantees that the value can be moved by its bits
  from one location to another without causing any side effects.

- The `AnyType` trait defines the alias `__del__is_trivial`, which is a hint
  that the `__del__()` method is a no-op.
